#include "RingBuffer.h"

int32_t RingBufferCreateStatie(RingBuffer_t *RingBuf_handle, uint8_t *Buffer, uint32_t BufferLen)
{
    if (RingBuf_handle == NULL)
    {
        return RingBuf_ERROR;
    }

    RingBuf_handle->xSize        = 0;
    RingBuf_handle->xMAXItemSize = BufferLen;
    RingBuf_handle->pHead        = Buffer;
    RingBuf_handle->pTail        = Buffer + BufferLen;
    RingBuf_handle->pWrite       = Buffer;
    RingBuf_handle->pRead        = Buffer;

    return RingBuf_OK;
}

int32_t RingBufferWrite(RingBuffer_t *RingBuf_handle, const void *data, uint32_t count)
{
    if (count > (RingBuf_handle->xMAXItemSize - RingBuf_handle->xSize))
    {
        return RingBuf_NOMEM;
    }

    if ((RingBuf_handle->pTail - RingBuf_handle->pWrite) > count)
    {
        memcpy(RingBuf_handle->pWrite, data, count);

        RingBuf_handle->pWrite += count;
        RingBuf_handle->xSize += count;

        return RingBuf_OK;
    }
    else
    {
        uint32_t size1 = RingBuf_handle->pTail - RingBuf_handle->pWrite;
        uint32_t size2 = count - size1;

        memcpy(RingBuf_handle->pWrite, data, size1);
        memcpy(RingBuf_handle->pHead, data + size1, size2);

        RingBuf_handle->pWrite = RingBuf_handle->pHead + size2;
        RingBuf_handle->xSize += count;

        return RingBuf_OK;
    }
}

int32_t RingBufferRead(RingBuffer_t *RingBuf_handle, void *data, uint32_t count)
{
    if (RingBuf_handle->xSize == 0)
    {
        return RingBuf_EMPTY;
    }

    if (count > RingBuf_handle->xSize)
    {

        if ((RingBuf_handle->pTail - RingBuf_handle->pRead) < count)
        {
            uint32_t size1 = RingBuf_handle->pTail - RingBuf_handle->pRead;
            uint32_t size2 = RingBuf_handle->xSize - size1;

            memcpy(data, RingBuf_handle->pRead, size1);
            memcpy(data + size1, RingBuf_handle->pTail, size2);

            RingBuf_handle->pRead = RingBuf_handle->pHead + size2;
            RingBuf_handle->xSize = 0;

            return RingBuf_OK;
        }
        else
        {
            memcpy(data, RingBuf_handle->pRead, RingBuf_handle->xSize);

            RingBuf_handle->pRead += count;
            RingBuf_handle->xSize = 0;

            return RingBuf_OK;
        }
    }
    else
    {
        if ((RingBuf_handle->pTail - RingBuf_handle->pRead) < count)
        {
            uint32_t size1 = RingBuf_handle->pTail - RingBuf_handle->pRead;
            uint32_t size2 = count - size1;

            memcpy(data, RingBuf_handle->pRead, size1);
            memcpy(data + size1, RingBuf_handle->pHead, size2);

            RingBuf_handle->pRead = RingBuf_handle->pHead + size2;
            RingBuf_handle->xSize -= count;

            return RingBuf_OK;
        }
        else
        {
            memcpy(data, RingBuf_handle->pRead, RingBuf_handle->xSize);

            RingBuf_handle->pRead += count;
            RingBuf_handle->xSize -= count;

            return RingBuf_OK;
        }
    }
}
